#!/usr/bin/env python2.7
# -*- coding: utf-8 -*-
'''
Created on 19/08/2013

@author: Jesper Hertel.
'''

import re
import ComparableMixin  # For easy implementation of comparison.

class RevisionInfo(ComparableMixin.ComparableMixin):  # ComparableMixin to get comparison operators.
    '''

    Doctests:
        Normal RevisionInfo:
        >>> RevisionInfo(23, "2013-08-24")
        RevisionInfo(23, '2013-08-24')
        
        Large integer:
        >>> RevisionInfo(23423472934780239874, "2013-08-24")
        RevisionInfo(23423472934780239874, '2013-08-24')
    
        Equality:
        >>> RevisionInfo(22, "2013-08-24") == RevisionInfo(22, "2013-08-24")
        True
        >>> RevisionInfo(23, "2013-08-24") == RevisionInfo(22, "2013-08-24")
        False
        
        Sequential comparison:
        >>> RevisionInfo(23, "2013-08-24") > RevisionInfo(22, "2013-08-24")
        True
        >>> RevisionInfo(23, "2013-08-24") < RevisionInfo(24, "2013-08-25")
        True
    
        The version number has higher priority than the date:
        >>> RevisionInfo(23, "2000-01-01") > RevisionInfo(2, "2010-01-01")
        True
    '''

    def __init__(self, revisionNumber, isoDate):
        self.__revisionNumber = revisionNumber
        self.__isoDate = isoDate

    def getRevisionNumber(self):
        return self.__revisionNumber

    def getIsoDate(self):
        return self.__isoDate

    def setRevisionNumber(self, value):
        self.__revisionNumber = value

    def setIsoDate(self, value):
        self.__isoDate = value

    def _cmpkey(self):  # To make ComparableMixin.ComparableMixin work.
        return (self.__revisionNumber, self.__isoDate)
    
    def __str__(self):
        return "RevisionInfo(" + str(self.getRevisionNumber()) + ", '" + self.getIsoDate() + "')"
    
    def __repr__(self):
        return self.__str__()

    revisionNumber = property(getRevisionNumber, setRevisionNumber, None, '''Revision number as an integer value.''')
    isoDate = property(getIsoDate, setIsoDate, None, ''''Date of revision in ISO format, i.e. "2013-08-19".''')


def getRevisionFromRevisionTag(revisionTag):
    '''
    Return the revision number from a given version control system 
    revision tag.
    
    :param revisionTag:
        A string containing a revision tag from a versioning system
        with integer revisions (SVN, CVN) such as "$Revision$".
    '''    
    # Take only the digits from the string.
    # Thanks to http://stackoverflow.com/a/1812153/1629102.
    digitsOnlyString = filter(str.isdigit, revisionTag)
    try:
        # Make the digits into an integer to be able to compare versions directly.
        revisionNumber = int(digitsOnlyString)
    except ValueError:  # No digits.
        revisionNumber = None
    return revisionNumber

def getIsoDateFromDateTag(dateTag):
    '''
    
    :param dateTag:
        Any string with an iso formatted date (yyyy-mm-dd) in it.
    :type dateTag:
        String
    
    Doctest:
    >>> getIsoDateFromDateTag('#Date: 2013-08-19 20:07:12 +0200 (ma, 19 aug 2013) $')
    '2013-08-19'
    >>> getIsoDateFromDateTag('')
    >>> getIsoDateFromDateTag('2013-08-20')
    '2013-08-20'
    >>> getIsoDateFromDateTag('anything2013-08-19anything')
    '2013-08-19'
    ''' 
    
    matchObject = re.search("[0-9][0-9][0-9][0-9]-[0-9][0-9]-[0-9][0-9]", dateTag)
    if matchObject: 
        isoDate = matchObject.group(0)  # Get the entire match.
    else:
        isoDate = None
    return isoDate

def getRevisionInfoFromTags(revisionTag, dateTag):
    revisionNumber = getRevisionFromRevisionTag(revisionTag)
    isoDate = getIsoDateFromDateTag(dateTag)
    return RevisionInfo(revisionNumber, isoDate)

_revisionInfo = getRevisionInfoFromTags('$Revision$', '$Date$')

def getHighestRevisionInfoFromModuleList(moduleList):
    if moduleList:
        highestRevisionInfoOfModuleList = reduce(max, [module._revisionInfo for module in moduleList])
    else:
        highestRevisionInfoOfModuleList = None
    return highestRevisionInfoOfModuleList  # A RevisionInfo object.

def getRevisionInfoFromTagsAndSubModules(revisionTag, dateTag, _submoduleListForVersioning):
    moduleRevisionInfoFromTag = getRevisionInfoFromTags(revisionTag, dateTag)
    highestRevisionInfoOfSubModules = getHighestRevisionInfoFromModuleList(_submoduleListForVersioning)
    thisModuleRevisionInfo = _revisionInfo
    revisionInfo = max(moduleRevisionInfoFromTag, highestRevisionInfoOfSubModules, thisModuleRevisionInfo)
    return revisionInfo  # A RevisionInfo object.
